public class Code1 {
    // 乘积最大子数组

    public int maxProduct(int[] nums) {
        // 创建 dp 表
        // 初始化
        // 填表
        // 确定返回值

        int n = nums.length;
        // 分析题目，这里需要计算的是从子数组中获取最大的乘积
        // 这道题目与前面写的计算 最大子数组的加和 比较相似但是在细节上还是有不同
        // f[i] 表示的是，以 i 位置为结尾的所有子数组中的 最大乘积
        int[] f = new int[n + 1];
        // 我们需要知道的是 对于 f 表后面的填写，是需要依据当前的 nums 表中的数据相乘来进行获取。
        // 但是 f 表中存储的是当前所获取到的乘积的最大值，此时若 nums 表中存储的是一个 “负值” 相乘就会出现一个相当小的值
        // 此时就需要一个 g 表，g[i] 表示的是当前以 i 位置为结尾的所有子数组中的最小乘积
        int[] g = new int[n + 1];

        // 进行初始化操作
        // 为了确保 f、g 表中获取到的信息不被初始值篡改，这里将虚拟节点位置的值初始化为 1
        f[0] = g[0] = 1;

        // 进行填表操作
        // 两个表同时填写，从左向右开始
        for(int i = 1; i <= n; i++){
            // 针对 f 表的填写进行简单分析
            // 当选择的 nums 的长度为 1 时，此时填入表的最大值为 nums[i]
            // 当此时选择的是 nums[i] 位置前面的值，长度大于 1 时，要考虑两方面
            // 当 nums[i]>0 时，此时填入表的值为 f[i - 1]*nums[i]
            // 当 nums[i]<0 时，此时填入表的值为 g[i - 1]*nums[i]
            f[i] = Math.max(nums[i - 1], Math.max(f[i - 1]*nums[i - 1], g[i - 1]*nums[i - 1]));
            // 同理 g 表的逻辑只需要反过来即可
            g[i] = Math.min(nums[i - 1], Math.min(f[i - 1]*nums[i - 1], g[i - 1]*nums[i - 1]));
        }
        // 返回值获取到的应该是 f 表中的最大值
        int ret = Integer.MIN_VALUE;
        // 这里需要注意的是要从 1 开始 f[0] 在一开始就被初始化为 1 了
        for(int j = 1; j <= n; j++){
            ret = Math.max(ret, f[j]);
        }
        return ret;
    }
}
